/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 * 
 */
package com.ucjava.chat.commserve.rmi.server;

import com.ucjava.chat.admanager.AdvertisingImpl;
import com.ucjava.chat.admanager.IAdvertising;
import com.ucjava.chat.commserve.rmi.common.IChatClientRMI;
import com.ucjava.chat.commserve.rmi.common.IChatService;
import com.ucjava.chat.commserve.rmi.common.Message;
import com.ucjava.chat.commserve.rmi.common.OwnIP;
import com.ucjava.chat.commserve.rmi.common.PrefStore;
import com.ucjava.chat.commserve.rmi.common.PrivacySettings;
import com.ucjava.chat.commserve.rmi.common.RMIChatConstants;
import com.ucjava.chat.commserve.rmi.common.ResultCodes;
import com.ucjava.chat.socialnetworking.contacts.ContactsImpl;
import com.ucjava.chat.socialnetworking.contacts.IContacts;
import com.ucjava.chat.socialnetworking.contacts.IMyFriends;
import com.ucjava.chat.socialnetworking.contacts.ISuggestedFriends;
import com.ucjava.chat.socialnetworking.contacts.MyFriends;
import com.ucjava.chat.socialnetworking.contacts.SuggestedFriends;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.SocketException;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RemoteServer;
import java.rmi.server.ServerNotActiveException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ChatServiceImpl extends UnicastRemoteObject implements IChatService {

    private ClientHandler clientTracker;
    private MessageArchiver messageArchiver;
    private PrefStore prefStore;

    //Finds and sets available socket.
    public ServerSocket create(int[] ports) throws IOException {
        for (int port : ports) {
            try {
                return new ServerSocket(port);
            } catch (IOException ex) {
                continue; // try next port
            }
        }

        // if the program gets here, no port in the range was found
        throw new IOException("no free port found");
    }  
    
    private Registry startRegistry() throws RemoteException {
            
            try {
                //Set of sockets to attempt a connection.
                ServerSocket soc = create(new int[] {1099, 1111, 1100, 1254, 3843, 4580, 6754, 3456 });
                System.out.println("listening on port: " + soc.getLocalPort());
                final int PORT = soc.getLocalPort();
                //Close socket.
                soc.close();
                return LocateRegistry.createRegistry(PORT); 
                } 
            catch (IOException e) {
                //If none of the availible sockets work then it will display and error and just try and bail out with a default.
                 System.err.println("no available ports");
                 return LocateRegistry.createRegistry(1099);          
            }       
    }  
    //private MessageHarvester msgHarvester = new MessageHarvester();
    // Constructor

    public ChatServiceImpl()
            throws RemoteException {
        super();
        clientTracker = new ClientHandler();
        messageArchiver = new MessageArchiver();

        if (System.getSecurityManager() == null) {

            System.setSecurityManager(new RMISecurityManager());
        }

        OwnIP ownIP = null;
        try {
            ownIP = OwnIP.buildOwnIP();
            System.out.println("Our IP: " + ownIP.getIP());
        } catch (SocketException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Could not determine our IP!");
            System.exit(1);
        }
        // Set this property so RMI calls below
        // will "export" proper ip address when
        // clients create server stubs:
        System.setProperty("java.rmi.server.hostname",
                ownIP.getIP());

        try {
            // Find the RMI registry:
            //Registry registry = LocateRegistry.getRegistry();
            Registry registry = startRegistry();
            // Bind ourselves to the registry:
            registry.rebind(RMIChatConstants.SERVICENAME,
                    (IChatService) this);

            // Binds Contacts (Used by Social Networking Team)
            IContacts c = new ContactsImpl();
            registry.rebind(ContactsImpl.ALLCONTACTS, c);
            // Binds MyFriends (Used by Social Networking Team)
            IMyFriends mf = new MyFriends();
            registry.rebind(MyFriends.MYFRIENDS, mf);
            // Binds SuggestedFriends (Used by Social Networking Team)
            ISuggestedFriends sf = new SuggestedFriends();
            registry.rebind(SuggestedFriends.SUGGESTEDFRIENDS, sf);
            // (End Social Networking component)

            //rebind for the advertising portion of the program
            IAdvertising ad = new AdvertisingImpl();
            registry.rebind(AdvertisingImpl.PURCHASEADVERTISEMENTS, ad);

            System.err.println();
        } // end try
        catch (RemoteException e) {
            System.err.println("Server exception: " + e.toString());
            e.printStackTrace();
            System.exit(3);
        } // end catch
    }

    /*Method to login to RMI Host. 
     * @param username Client Username
     * @param password Client Password
     * @param rcvMsgStub 
     * @throws RemoteException
     * 
     */
    @Override
    public ResultCodes login(String username, String password,
            IChatClientRMI rcvMsgStub) throws RemoteException {
        String host = null;
        try {
            // Use RMI method to find out where this call came from:
            host = RemoteServer.getClientHost();
        } catch (ServerNotActiveException ex) {
            Logger.getLogger(ChatServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
        // Pass the login request off to clientTracker:
        return clientTracker.doLogin(username, password, host, rcvMsgStub);
    }

    @Override
    public ResultCodes logout(String username) throws RemoteException {
        // Pass the logout request off to clientTracker:
        return clientTracker.doLogout(username);
    }

    /**
     * The name of this method is a bit ambiguous -- send from where to where?
     * In fact, this method is called by the client and sends a message from the
     * client to the server.
     *
     * After verifying that sender is logged in, add message to
     * MessageArchiver's sendingQueue.
     *
     * @param msg
     * @param username
     * @return
     * @throws RemoteException
     */
    @Override
    public ResultCodes sendMessage(Message msg, String username) throws RemoteException {
        // Get the LoggedInClient object corresponding to this username:
        LoggedInClient cl = clientTracker.clientForName(username);
        if (cl == null) {
            return ResultCodes.NOT_LOGGED_IN;
        } else {
            // This client is logged in. "Touch" the client's last access time
            cl.updateAccessTime();

            // Put the message into the "outboxes" of all
            // currently logged-in clients:
            clientTracker.dispatchMessage(msg);
            // Save a copy in archiving queue:
            messageArchiver.enqueueMessage(msg);
            // Some debugging output:
            System.out.println("DEBUG: Received msg");
            System.out.println("from " + msg.getSender().getUserName());
            System.out.println("contents: " + msg.getContent());

            // Return success code:        
            return ResultCodes.MSG_SENT_OK;
        }
    }
    /*
     * Method to get logged in client names. Stores that collection in an arraylsit and then loops through the
     * arraylist, storing each object in a String[] array. 
     @return String[]
     */

    @Override
    public String[] getLoggedInClientNames() throws RemoteException {
        ArrayList<LoggedInClient> arrayList =
                clientTracker.getLoggedInClients();
        String[] strArray = new String[arrayList.size()];
        LoggedInClient cl;
        for (int i = 0; i < arrayList.size(); i++) {
            cl = arrayList.get(i);
            if (cl.getRcvMsgStub().getPrivacySetting() == PrivacySettings.OPEN) {
                strArray[i] = arrayList.get(i).getUsername();
            }
        }
        return strArray;
    }
} // end Class
